package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import interfaces.DataBuffer;
import interfaces.TagDataChangedEvent;
import interfaces.TagDataChangedListener;
import interfaces.TagDataGetter;
import interfaces.TagDataSetter;

/**
 * @author Manseer Marcel  
 * @author Plavsic Maja
 * @author Pretsch Paul
 */
public abstract class BaseDataBuffer implements DataBuffer, TagDataChangedListener {

	private List<TagDataChangedListener> _listeners = new ArrayList<TagDataChangedListener>();
	
	/**
	 * @param from begin of time span
	 * @param to end of time span
	 * @param tags all tags that should be in result
	 * @return all TagData for time span and tags
	 */
	protected abstract List<TagData> getTagData(Date from, Date to, String... tags);

	/* (non-Javadoc)
	 * @see model.DataBuffer#getDataSetter(java.lang.String, java.util.Date)
	 */
	@Override
	public synchronized TagDataSetter getDataSetter(String tag, Date date) {
		List<TagData> tmp = getTagData(date, date, tag);
		
		switch (tmp.size()) {
		case 1: 
			return tmp.get(0);
		case 0: 
			TagData tagData = new TagData(tag, date, this);
			addData(tagData);
			return tagData;
		default:
			throw new IndexOutOfBoundsException("size > 0");
		}		
	}
	
	@Override
	public void removeData(Date date, String hashtag) {
		List<TagData> tagData = getTagData(date, date, hashtag);
		for (TagData data : tagData) {
			removeData(data);
		}
	}
	
	protected abstract void addData(TagData tagData);
	protected abstract void removeData(TagData tagData);

	/* (non-Javadoc)
	 * @see model.DataBuffer#getNewDataSetter(java.lang.String, java.util.Date)
	 */
	@Override
	public TagDataSetter getNewDataSetter(String tag, Date date) {
		List<TagData> tmp = getTagData(date, date, tag);
		
		switch (tmp.size()) {
		case 1: 
			return null;
		case 0: 
			TagData tagData = new TagData(tag, date, this);
			addData(tagData);
			return tagData;
		default:
			throw new IndexOutOfBoundsException("size > 0");
		}
	}
	

	/* (non-Javadoc)
	 * @see model.DataBuffer#getTwitterData(java.util.Date, java.lang.String[])
	 */
	@Override
	public List<TagDataGetter> getTwitterData(Date date, String... tags) {
		return getTwitterData(date, date, tags);
	}

	/* (non-Javadoc)
	 * @see model.DataBuffer#getTwitterData(java.util.Date, java.util.Date, java.lang.String[])
	 */
	@Override
	public List<TagDataGetter> getTwitterData(Date from, Date to, String... tags) {
		List<TagData> tmp = getTagData(from, to, tags);
		List<TagDataGetter> tmp2 = new ArrayList<TagDataGetter>();
		
		for (TagData tagData : tmp) {
			tmp2.add(tagData);
		}
		return Collections.unmodifiableList(tmp2);
	}


	/* (non-Javadoc)
	 * @see interfaces.DataBuffer#addTagDataChangedListener(interfaces.TagDataChangedListener)
	 */
	@Override
	public void addTagDataChangedListener(TagDataChangedListener listener) {
		_listeners.add(listener);
	}
	
	/* (non-Javadoc)
	 * @see interfaces.DataBuffer#fireTagDataChanged(interfaces.TagDataGetter)
	 */
	public final void fireTagDataChanged(TagDataGetter tagData, int oldCount)
	{
		Iterator<TagDataChangedListener> i = _listeners.iterator();
	    while(i.hasNext())	{
	      ((TagDataChangedListener) i.next()).handleTagDataChanged(new TagDataChangedEvent(tagData, oldCount));
	    }
	}
	
	/* (non-Javadoc)
	 * @see interfaces.TagDataChangedListener#handleTagDataChanged(interfaces.TagDataChangedEvent)
	 */
	@Override
	public void handleTagDataChanged(TagDataChangedEvent e) {
		fireTagDataChanged((TagDataGetter) e.getSource(), e.getOldCount());
	}	
}
